#ifndef sio_h
#define sio_h


#include <stddef.h>


#ifndef SIO_API
#  define SIO_API
#endif /* SIO_API */

#ifndef SIO_BUFSIZ
#  define SIO_BUFSIZ 512
#endif /* SIO_BUFSIZ */


typedef struct SIO SIO;

typedef void sio_Deletor(SIO *io);
typedef const char *sio_Reader(SIO *io, size_t *psz);
typedef size_t sio_Writer(SIO *io, const char *buff, size_t size);

struct SIO {
    sio_Deletor *deletor;
    sio_Reader *reader;
    sio_Writer *writer;
    const char *p, *buff, *buffend;
    const char *errmsg;
    int errnum;
    char rwbuff[SIO_BUFSIZ];
};

#define sio_clearerror(io) ((void)((io)->errnum = 0, (io)->errmsg = NULL))
#define sio_seterror(io,en,em) ((void)((io)->errnum=(en),(io)->errmsg=(em)))
#define sio_geterror(io,perr) ((void)(perr && *perr = (io)->errnum), (io)->errmsg)

#define sio_setdeletor(io, d) ((io)->deletor = (d))

SIO_API SIO *sio_init(SIO *io);
SIO_API void sio_cleanup(SIO *io);

SIO_API void sio_setreader(SIO *io, sio_Reader *reader);
SIO_API void sio_setwriter(SIO *io, sio_Writer *writer);


/* read operations */

#define sio_peek(io) ((io)->p != NULL ? *(io)->p : 0)
#define sio_next(io) ((io)->p == (io)->buffend ? sio_fill(io) : (++(io)->p, 1))

SIO_API int sio_fill(SIO *io);

SIO_API int sio_readint(SIO *io, int base, size_t *pcount);
SIO_API double sio_readfloat(SIO *io, size_t *pcount);

SIO_API int sio_readint_binary(SIO *io, int bigendian, size_t count);
SIO_API double sio_readfloat_binary(SIO *io, int bigendian, size_t count);

SIO_API size_t sio_read(SIO *io, char *buff, size_t sz);


/* write operations */

#define sio_writechar(io, ch) \
    (((io)->p < (io)->buffend || sio_flush(io)) && (*(char*)(io)->p++ = (ch), 1))

SIO_API size_t sio_flush(SIO *io);

SIO_API size_t sio_writeint(SIO *io, int num, int base);
SIO_API size_t sio_writefloat(SIO *io, double num, int base);

SIO_API size_t sio_writebinary_int(SIO *io, int num, int endian, int count);
SIO_API size_t sio_writebinary_float(SIO *io, double num, int endian, int count);

SIO_API size_t sio_write(SIO *io, const char *buff, size_t sz);


/* ordinary creators */

SIO_API SIO *sio_from_filename(const char *fn, int binary);
SIO_API SIO *sio_from_buffer(const char *buff, size_t len);
SIO_API SIO *sio_from_FILE(void *fp);

SIO_API SIO *sio_to_filename(const char *fn, int binary);
SIO_API SIO *sio_to_buffer(char *buff, size_t len);
SIO_API SIO *sio_to_FILE(void *fp);


#endif /* sio_h */
